#include "Scene/Camera.h"

namespace vital {

	//--------------------------------------------------------------------------
	TCamera::TCamera() {

		mFov = Math::PI * 0.25f;
		mAspect = 1.0f;
		mZNear = 1.0f;
		mZFar = 200.0f;

		mProjMode = PERSPECTIVE;

		mReflectMtxEnabled = false;

		mReflectMtx = identity4();

		mViewParamDirty = true;
	}

	//--------------------------------------------------------------------------
	TCamera::~TCamera() {

	}

	//--------------------------------------------------------------------------
	TMtx4 TCamera::getViewMatrix() {

		TMtx4 mtx = getWorldTransform();

		TMtx3 rot_t;
		rot_t.set(
			mtx[0][0], mtx[1][0], mtx[2][0],
			mtx[0][1], mtx[1][1], mtx[2][1],
			mtx[0][2], mtx[1][2], mtx[2][2]
		);

		TVec3 pos(mtx[0][3], mtx[1][3], mtx[2][3]);

		pos = rot_t * pos;

		TMtx4 viewMtx;
		viewMtx.set(
			rot_t[0][0], rot_t[0][1], rot_t[0][2], -pos[0],
			rot_t[1][0], rot_t[1][1], rot_t[1][2], -pos[1],
			rot_t[2][0], rot_t[2][1], rot_t[2][2], -pos[2],
			0.0f, 0.0f, 0.0f, 1.0f );

		if(mReflectMtxEnabled)
			viewMtx = viewMtx * mReflectMtx;

		return viewMtx;
	}

	//--------------------------------------------------------------------------
	TMtx4 TCamera::getProjMatrix() {

		updateProjectionMatrix();

		if(PERSPECTIVE == mProjMode)
			return mProjMtxP;

		return mProjMtxO;
	}

	//--------------------------------------------------------------------------
	void TCamera::setViewParam(float fov, float apsect, float zNear, float zFar) {

		mFov = fov;
		mAspect = apsect;
		mZNear = zNear;
		mZFar = zFar;

		mViewParamDirty = true;
	}

	//--------------------------------------------------------------------------
	void TCamera::updateProjectionMatrix() {

		if(mViewParamDirty) {

			// perspective
			mProjMtxP = identity4();

			float f = 1.0f / tanf( mFov );
			float d = 1.0f / (mZNear - mZFar);

			mProjMtxP[0][0] = f / mAspect;
			mProjMtxP[1][1] = f;
			mProjMtxP[2][2] = (mZFar + mZNear) * d;
			mProjMtxP[2][3] = (2.0f * mZFar * mZNear) * d;
			mProjMtxP[3][2] = -1.0f;

			// orthographic
			mProjMtxO = identity4();

			float farHeight = f * mZFar * 0.5f;
			float farWidth = farHeight / mAspect;

			mProjMtxO[0][0] = 2.0f / farWidth;
			mProjMtxO[1][1] = 2.0f / farWidth;
			mProjMtxO[2][2] = 2.0f * d;
			mProjMtxO[2][3] = (mZFar + mZNear) * d;

			mViewParamDirty = false;
		}
	}

	//--------------------------------------------------------------------------
	TCamera::PROJECTION_MODE TCamera::getProjectionMode() {

		return mProjMode;
	}

	//--------------------------------------------------------------------------
	void TCamera::toggleProjectionMode() {

		if( PERSPECTIVE == mProjMode )
			mProjMode = ORTHOGRAPHIC;
		else
			mProjMode = PERSPECTIVE;
	}

	//--------------------------------------------------------------------------
	void TCamera::setProjectionMode(PROJECTION_MODE mode) {

		mProjMode = mode;
	}

	//--------------------------------------------------------------------------
	bool TCamera::getReflectMtxEnabled() {

		return mReflectMtxEnabled;
	}

	//--------------------------------------------------------------------------
	void TCamera::setReflectMtxEnabled(bool value) {

		mReflectMtxEnabled = value;
	}

	//--------------------------------------------------------------------------
	void TCamera::buildReflectMtx(const TVec4 &reflectPlane) {

		mReflectMtx.set(
			1.0f, 0.0f, 0.0f, 0.0f,
			0.0f,-1.0f, 0.0f, 0.0f,
			0.0f, 0.0f, 1.0f, 0.0f,
			0.0f, 0.0f, 0.0f, 1.0f);
	}

	//--------------------------------------------------------------------------

}